package com.blockmeta.bbs.immodule.widget.chatboard;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.blockmeta.bbs.baselibrary.utils.SharedPreferenceUtil;
import com.blockmeta.bbs.baselibrary.utils.TimeUtil;
import com.blockmeta.bbs.baselibrary.utils.ToastUtil;
import com.blockmeta.bbs.baselibrary.widget.ToggleScrollViewPager;
import com.blockmeta.bbs.baselibrary.utils.OpenFileUtil;
import com.blockmeta.bbs.businesslibrary.widget.emoji.EmojiEditText;
import com.blockmeta.bbs.businesslibrary.widget.emoji.EmojiImageView;
import com.blockmeta.bbs.businesslibrary.widget.emoji.OnEmojiClickListener;
import com.blockmeta.bbs.businesslibrary.widget.emoji.OnMediaClickListener;
import com.blockmeta.bbs.immodule.R;
import com.blockmeta.bbs.immodule.dao.ChatMessage;
import com.blockmeta.bbs.immodule.interfaces.OnEmojiButtonClickListener;
import com.vanniktech.emoji.emoji.Emoji;

import java.io.File;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;

import static android.view.View.NO_ID;

/**
 * @author AirThor
 * @date 2019/2/22.
 * 聊天输入框
 */
public abstract class BaseChatBoard extends Fragment implements TextView.OnEditorActionListener, View.OnClickListener, View.OnTouchListener
        , OnEmojiClickListener, OnEmojiButtonClickListener, OnMediaClickListener {
    public static final String SOFT_INPUT_HEIGHT = "softInputHeight";

    protected final static int NO_AREA = -1;
    /**
     * 软键盘默认高度
     */
    private static final int DEFAULT_HEIGHT = 500;

    private Context mContext;
    /**
     * 简单工厂类用来创建输入框不同功能区，比如emoji区，发图片视频功能入口区
     * 不同的区为不同的fragment
     */
    private IChatBoardFactory mChatBoardFactory;
    /**
     * 承载不同的功能区
     */
    private ToggleScrollViewPager mViewPager;
    /**
     * 输入框
     */
    public EmojiEditText mInput;
    /**
     * 软键盘管理类
     */
    private InputMethodManager mInputMethodManager;

    /**
     * 和输入框绑定的内容布局
     */
    private View mContentView;
    /**
     * 功能区fragment
     */
    private List<Fragment> mFragments;

    protected OnOutPutListener mOnOutPutListener;

    private ChatBoardTagHelper mChatBoardTagHelper;

    protected long mLastSendTime;
    @Override
    public void onAttach(Context context) {
        mContext = getActivity();
        super.onAttach(context);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.view_chatboard, null);
        ((ViewGroup)view).addView(getInputAreaView(),0);
        init(view);
        return view;
    }

    /**
     * 输入区域view，样式交给子 view定义
     * @return view
     */
    protected abstract View getInputAreaView();

    /**
     * 输入框由子view定义并返回
     * @param view 根布局
     * @return mInput
     */
    protected abstract EmojiEditText getInputView(View view);

    @SuppressLint("ClickableViewAccessibility")
    protected void init(View view) {
        //设置软件盘的模式：SOFT_INPUT_ADJUST_RESIZE  这个属性表示Activity的主窗口总是会被调整大小，从而保证软键盘显示空间。
        //从而方便我们计算软件盘的高度
        ((Activity) mContext).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN |
                WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

        mViewPager = view.findViewById(R.id.vp_multi_board);

        mInput = getInputView(view);
        mInput.setMaxLines(Integer.MAX_VALUE);
        mInput.setHorizontallyScrolling(false);
        mInput.setOnEditorActionListener(this);
        mInput.setOnTouchListener(this);
        if (mChatBoardFactory==null){
            mChatBoardFactory = ChatBoardFactory.getInstance();
        }
        mFragments = mChatBoardFactory.getFragments();
        mViewPager.setCanScroll(false);
        mViewPager.setAdapter(new EmojiViewPagerAdapter(((FragmentActivity) mContext).getSupportFragmentManager()));

        mInputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        fixMemoryLeak(mInputMethodManager);

        //隐藏软件盘
        hideSoftInput();

        mChatBoardTagHelper = new ChatBoardTagHelper(mContext, mInput);
    }

    /**
     * 修复个别机型上（如华为手机）InputMethodManager引起的内存泄漏
     * @param inputMethodManager
     */
    protected  void fixMemoryLeak(InputMethodManager inputMethodManager){
        Field field = null;
        try {
            field = inputMethodManager.getClass().getField("mLastSrvView");
            field.setAccessible(true);
            field.set(inputMethodManager,null);
        } catch (Exception e ) {
            e.printStackTrace();
        }
    }


    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        boolean backValue = actionId == EditorInfo.IME_ACTION_SEND;
        if (backValue && mOnOutPutListener != null) {
            String content = mChatBoardTagHelper.getInputText(true);
            if (!TextUtils.isEmpty(content)) {
                if (sendSpeedControl()) {
                    return backValue;
                }
                mOnOutPutListener.onOutPutText(ChatMessage.CONTENT_TYPE_NORMAL, 0, content);
                mInput.setText("");
            }
        }
        return backValue;
    }

    private boolean sendSpeedControl() {
        //限制一秒最多发一条
        long nowTime = TimeUtil.getSeconds();
        if(nowTime < mLastSendTime + 1){
            ToastUtil.show("发送太频繁");
            return true;
        }
        mLastSendTime = nowTime;
        return false;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getActionMasked();
        if (action == MotionEvent.ACTION_UP) {
            if (mViewPager.isShown()) {
                //显示软件盘时，锁定内容高度，防止跳闪。
                lockContentHeight();
                //隐藏表情布局，显示软件盘
                resetToolAreaState();
                switchEmotionLayout(true);
                //软件盘显示后，释放内容高度
                mInput.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        unlockContentHeightDelayed();
                    }
                }, 200L);
            }
        }
        return false;
    }


    /**
     * 供外部调用隐藏输入框
     */
    public void hideKeyBoard() {
        mViewPager.setVisibility(View.GONE);
        resetToolAreaState();
        hideSoftInput();
    }

    /**
     * 表情点击后的回掉 设置给editText
     *
     * @param emoji
     * @param imageView
     */
    @Override
    public void onEmojiClick(@NonNull EmojiImageView imageView, @NonNull Emoji emoji) {
        mInput.input(emoji);
        imageView.updateEmoji(emoji);
    }
    @Override
    public void onEmojiButtonClickListener(View view) {
        int i = view.getId();
        if (i == R.id.iv_delete) {
            mInput.backspace();
        } else if (i == R.id.tv_send_content) {
            String content = mChatBoardTagHelper.getInputText(true);
            if (!TextUtils.isEmpty(content)) {
                if (sendSpeedControl()) {
                    return;
                }
                mOnOutPutListener.onOutPutText(ChatMessage.CONTENT_TYPE_NORMAL, 0, content);
                mInput.setText("");
            }
        }
    }

    @Override
    public void onMediaClick(View view, String content) {
        if (mOnOutPutListener != null) {
            resetToolAreaState();
            mViewPager.setVisibility(View.GONE);

            int chatMessageFileType = ChatMessage.getChatMessageFileType(OpenFileUtil.getExtensionName(content));
            mOnOutPutListener.onOutPutFile(chatMessageFileType, content);
        }
    }



    public interface OnOutPutListener {
        /**
         * 在点击发送时editText的内容通过此接口对外输出，怎么处理内容交给外部处理
         *
         * @param subType
         * @param content 内容
         */
        void onOutPutText(int type, int subType, String content);

        /**
         * 图片或文件
         * @param type
         * @param url
         */
        void onOutPutFile(int type,  String url);

        /**
         * 语音或视频输出
         * @param type
         * @param file
         */
        void onOutPutFile(int type,  File file);

        /**
         * 与外部页面的交互
         * @param eventType
         */
        void onChatBoardEvent(@KeyboardEvent.EventKind int eventType);
    }

    public void setOnOutPutListener(OnOutPutListener onOutPutListener) {
        mOnOutPutListener = onOutPutListener;
    }

    public OnOutPutListener getOnOutPutListener() {
        return mOnOutPutListener;
    }

    /**
     * 绑定到内容布局
     *
     * @param contentView
     * @return
     */
    public BaseChatBoard bindToContent(View contentView) {
        mContentView = contentView;
        mContentView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (mViewPager.getVisibility() == View.VISIBLE) {
                    mViewPager.setVisibility(View.GONE);
                }
                hideSoftInput();
                return false;
            }
        });
        return this;
    }

    public BaseChatBoard build() {
        //设置软件盘的模式：SOFT_INPUT_ADJUST_RESIZE  这个属性表示Activity的主窗口总是会被调整大小，从而保证软键盘显示空间。
        //从而方便我们计算软件盘的高度
        ((Activity) mContext).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN |
                WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        //隐藏软件盘
        hideSoftInput();
        return this;
    }

    /**
     * 获取软件盘的高度
     *
     * @return
     */
    private int getSupportSoftInputHeight() {
        Rect r = new Rect();
        /**
         * decorView是window中的最顶层view，可以从window中通过getDecorView获取到decorView。
         * 通过decorView获取到程序显示的区域，包括标题栏，但不包括状态栏。
         */
        ((Activity) mContext).getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
        //获取屏幕的高度
        int screenHeight = ((Activity) mContext).getWindow().getDecorView().getRootView().getHeight();
        //计算软件盘的高度
        int softInputHeight = screenHeight - r.bottom;

        /**
         * 某些Android版本下，没有显示软键盘时减出来的高度总是144，而不是零，
         * 这是因为高度是包括了虚拟按键栏的(例如华为系列)，所以在API Level高于20时，
         * 我们需要减去底部虚拟按键栏的高度（如果有的话）
         */
        if (isNavigationBarExist((Activity) mContext)) {
            // When SDK Level >= 20 (Android L), the softInputHeight will contain the height of softButtonsBar (if has)
            softInputHeight = softInputHeight - getSoftButtonsBarHeight();
        }
        //存一份到本地
        if (softInputHeight > 0) {
            SharedPreferenceUtil.putInt(mContext, SOFT_INPUT_HEIGHT, softInputHeight);
        }

        return softInputHeight;

    }

    private static final String NAVIGATION = "navigationBarBackground";

    /**
     * 该方法需要在View完全被绘制出来之后调用，否则判断不了
     * 在比如 onWindowFocusChanged（）方法中可以得到正确的结果
     */
    private static boolean isNavigationBarExist(@NonNull Activity activity) {
        ViewGroup vp = (ViewGroup) activity.getWindow().getDecorView();
        if (vp != null) {
            for (int i = 0; i < vp.getChildCount(); i++) {
                vp.getChildAt(i).getContext().getPackageName();
                if (vp.getChildAt(i).getId() != NO_ID && NAVIGATION.equals(activity.getResources().getResourceEntryName(vp.getChildAt(i).getId()))) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * 底部虚拟按键栏的高度
     *
     * @return
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private int getSoftButtonsBarHeight() {
        DisplayMetrics metrics = new DisplayMetrics();
        //这个方法获取可能不是真实屏幕的高度
        ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int usableHeight = metrics.heightPixels;
        //获取当前屏幕的真实高度
        ((Activity) mContext).getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
        int realHeight = metrics.heightPixels;
        if (realHeight > usableHeight) {
            return realHeight - usableHeight;
        } else {
            return 0;
        }
    }

    /**
     * 获取软键盘高度，由于第一次直接弹出表情时会出现小问题，500是一个均值，作为临时解决方案
     *
     * @return
     */
    private int getKeyBoardHeight() {
        return SharedPreferenceUtil.getInt(mContext, SOFT_INPUT_HEIGHT, DEFAULT_HEIGHT);
    }

    /**
     * 点击返回键时先隐藏表情布局
     *
     * @return
     */
    public boolean interceptBackPress() {
        if (mViewPager.isShown()) {
            resetToolAreaState();
            switchEmotionLayout(false);
            return true;
        }
        return false;
    }

    private void showEmotionLayout() {
        int softInputHeight = getSupportSoftInputHeight();
        if (softInputHeight <= 0) {
            softInputHeight = getKeyBoardHeight();
        }
        hideSoftInput();
        mViewPager.getLayoutParams().height = softInputHeight;
        mViewPager.setCurrentItem(whichToolAreaShow(), false);
        mViewPager.setVisibility(View.VISIBLE);
    }

    /**
     * 切换功能区
     *
     * @param showSoftInput 是否显示软件盘
     */
    private void switchEmotionLayout(boolean showSoftInput) {
        if (mViewPager.isShown()) {
            if (whichToolAreaShow() == -1) {
                mViewPager.setVisibility(View.GONE);
                if (showSoftInput) {
                    showSoftInput();
                }
            } else {
                mViewPager.setCurrentItem(whichToolAreaShow(), false);
            }
        }
    }

    /**
     * 重置所有功能按钮的状态
     */
    protected abstract void resetToolAreaState();
    /**
     * 锁定内容高度，防止跳闪
     */
    private void lockContentHeight() {
        if (getKeyBoardHeight() == DEFAULT_HEIGHT) {
            return;
        }
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mContentView.getLayoutParams();
        params.height = mContentView.getHeight();
        params.weight = 0.0F;
    }

    /**
     * 释放被锁定的内容高度
     */
    private void unlockContentHeightDelayed() {
        mInput.postDelayed(new Runnable() {
            @Override
            public void run() {
                ((LinearLayout.LayoutParams) mContentView.getLayoutParams()).weight = 1.0F;
            }
        }, 200L);
    }

    /**
     * 编辑框获取焦点，并显示软件盘
     */
    private void showSoftInput() {
        mInput.requestFocus();
        mInput.post(new Runnable() {
            @Override
            public void run() {
                mInputMethodManager.showSoftInput(mInput, 0);
            }
        });
    }

    /**
     * 隐藏软件盘
     */
    private void hideSoftInput() {
        mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
    }

    /**
     * 软键盘是否处于显示状态
     *
     * @return
     */
    private boolean isSoftInputShown() {
        return getSupportSoftInputHeight() > 0;
    }

    /**
     * 哪个功能区正处于显示状态
     *
     * @return  -1 表示都没有显示，其它值由子view定义。
     */
    protected abstract int whichToolAreaShow();

    /**
     * viewpager适配器
     */
    class EmojiViewPagerAdapter extends FragmentPagerAdapter {

        public EmojiViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragments.get(position);
        }

        @Override
        public int getCount() {
            return mFragments == null ? 0 : mFragments.size();
        }
    }

    public void showPopup(String pTitleHint, String pType) {
        mChatBoardTagHelper.showPopup(pTitleHint, pType);
    }

    public void addType(String pType, String pRule, InputFieldQueryAdapter.InputQueryItemMode pMode, HashSet<InputFieldQueryItem> pHashSet) {
        mChatBoardTagHelper.addType(pType, pRule, pMode, pHashSet);
    }

    public void tag(String pType, String key){
        mChatBoardTagHelper.tag(pType, key);
    }

    public interface ContentCountListener {
        void onChange(int characterCount, int byteCount);
    }


    public void setSpecialInputListener(EmojiEditText.SpecialInputListener pListener, String specialStr) {
        mInput.setSpecialInputListener(pListener, specialStr);
    }

    public void setChatBoardFactory(IChatBoardFactory chatBoardFactory) {
        mChatBoardFactory = chatBoardFactory;
    }


    /**
     * 展示或者隐藏键盘和功能区
     */
    protected void showOrHideKeyboard(){
        if (mViewPager.isShown()) {
            //显示软件盘时，锁定内容高度，防止跳闪。
            lockContentHeight();
            //隐藏表情布局，显示软件盘
            switchEmotionLayout(true);
            //软件盘显示后，释放内容高度
            unlockContentHeightDelayed();
        } else {
            if (isSoftInputShown()) {
                //同上
                lockContentHeight();
                showEmotionLayout();
                unlockContentHeightDelayed();
            } else {
                //两者都没显示，直接显示表情布局
                showEmotionLayout();
            }
        }
    }
}
